package raytracer.misc;

import raytracer.math.Color3d;

/**
 * The balance of color-values and k-values is guaranteed by adjusting all the values
 * when one of the parameters is changed
 * @author Thorsten Roth
 * @version 07.06.2006
 */
public class Material {
	
	private Color3d oLocalColor,localColor;
	private Color3d oDiffuseColor,diffuseColor;
	private Color3d oSpecularColor,specularColor;
	private float kLocal;
	private float kDiffuse;
	private float kSpecular;
	private float kReflective;
	private float kTransparent;
	private int specPower;
	private float refrIndex;
	
	public Material(Material m) {
		this.oLocalColor=m.getLocalColor();
		this.oDiffuseColor=m.getDiffuseColor();
		this.oSpecularColor=m.getSpecularColor();
		this.specPower=m.getSpecPower();
		this.kLocal=m.getKLocal();
		this.kDiffuse=m.getKDiffuse();
		this.kSpecular=m.getKSpecular();
		this.kReflective=m.getKReflective();
		this.kTransparent=m.getKTransparent();
		this.refrIndex=1;
		normalize();		
	}
	
	public Material() {
		this.oLocalColor=new Color3d(1,1,1);
		this.oDiffuseColor=new Color3d(1,1,1);
		this.oSpecularColor=new Color3d(1,1,1);
		this.setSpecPower(100);
		this.setKLocal(.1f);
		this.setKDiffuse(.5f);
		this.setKSpecular(.4f);
		this.setKReflective(0);
		this.setKTransparent(0);
		this.refrIndex=1;
		normalize();
	}
	
	public void setLocalColor(Color3d color) {
		this.oLocalColor=color;
		normalizeColors();
	}
	
	public void	setDiffuseColor(Color3d color) {
		this.oDiffuseColor=color;
		normalizeColors();
	}
	
	public void setSpecularColor(Color3d color) {
		this.oSpecularColor=color;
		normalizeColors();
	}
	
	/**
	 * This method MUST be called if values for intensities don't sum up to 1
	 */
	public void normalize() {
		normalizeIntensities();
		normalizeColors();
	}
	
	private void normalizeIntensities() {
		float kTotal=kLocal+kDiffuse+kSpecular+kReflective;
		if (kTotal>0) {
			kLocal/=kTotal;
			kDiffuse/=kTotal;
			kSpecular/=kTotal;
			kReflective/=kTotal;
		}
		else {
			kLocal=0;
			kDiffuse=0;
			kSpecular=0;
			kReflective=0;
		}
	}
	
	private void normalizeColors() {
		localColor=new Color3d(oLocalColor);
		diffuseColor=new Color3d(oDiffuseColor);
		specularColor=new Color3d(oSpecularColor);
		
		//localColor.scale(kLocal);
		//diffuseColor.scale(kDiffuse);
		//specularColor.scale(kSpecular);
	}
	
	public void setKLocal(float kLocal) {
		this.kLocal=kLocal;
	}
	
	public void setKDiffuse(float kDiffuse) {
		this.kDiffuse=kDiffuse;
	}
	
	public void setKSpecular(float kSpecular) {
		this.kSpecular=kSpecular;
	}
	
	public void setKReflective(float kReflective) {
		this.kReflective=kReflective;
	}
	
	public void setKTransparent(float kTransparent) {
		this.kTransparent=Math.min(1,kTransparent);
	}
	
	public void setSpecPower(int specPower) {
		this.specPower=specPower;
	}
	
	public void setRefrIndex(float refrIndex) {
		this.refrIndex=refrIndex;
	}
	
	public Color3d getLocalColor() {
		return new Color3d(this.localColor);
	}
	
	public Color3d getDiffuseColor() {
		return new Color3d(this.diffuseColor);
	}
	
	public Color3d getSpecularColor() {
		return new Color3d(this.specularColor);
	}
	
	public float getKLocal() {
		return kLocal;
	}
	
	public float getKDiffuse() {
		return kDiffuse;
	}
	
	public float getKSpecular() {
		return kSpecular;
	}
	
	public float getKReflective() {
		return kReflective;
	}
	
	public float getRefrIndex() {
		return refrIndex;
	}
	
	public float getKTransparent() {
		return this.kTransparent;
	}
	
	public int getSpecPower() {
		return specPower;
	}
	
}
